#ifndef TB_ARCHIVE_MARSHAL_HPP__
#define TB_ARCHIVE_MARSHAL_HPP__

#include "../base/memory_buffer.hpp"
#include "../reflection/variant.hpp"

#include "stream/json_output_stream.hpp"
#include "proto/json_writer.hpp"
#include "proto/json_reader.hpp"
#include "proto/msgpack_reader.hpp"
#include "proto/msgpack_writer.hpp"
#include "serializer.hpp"
#include "archive_export.hpp"

TB_NAMESPACE_BEGIN

struct json_protocol_tag {};
struct msgpack_protocol_tag {};

template <typename Protocol>
struct Archive {
  template <typename WriteBuffer>
  static void Serialize(const Variant& obj, WriteBuffer& buf) {
    BOOST_STATIC_ASSERT(false);
    (void)obj, (void)buf;
  }

  template <typename ReadBuffer>
  static Variant Deserialize(ReadBuffer& buf) {
    BOOST_STATIC_ASSERT(false);
    (void)buf;
  }
};

template <>
struct Archive<json_protocol_tag> {
  template <typename WriteBuffer>
  static void Serialize(const Variant& obj, WriteBuffer& buf) {
    typedef JsonOutputStream<WriteBuffer> stream_type;

    typedef JsonWriter<stream_type> writer_type;

    typedef Serializer<writer_type> json_serializer;

    stream_type stream(buf);
    writer_type writer(stream);
    json_serializer ser(writer);

    ser.Serialize(obj);
    ser.Flush();
  }

  template <typename ReadBuffer>
  static Variant Deserialize(ReadBuffer& buf) {
    typedef JsonReader<ReadBuffer> reader_type;

    typedef Deserializer<ReadBuffer, reader_type> json_deserializer;

    return json_deserializer::Deserialize(buf);
  }
};

template <>
struct Archive<msgpack_protocol_tag> {
  template <typename WriteBuffer>
  static void Serialize(const Variant& obj, WriteBuffer& buf) {
    typedef MsgPackWriter<WriteBuffer> writer_type;

    typedef Serializer<writer_type> msgpack_serializer;

    writer_type writer(buf);
    msgpack_serializer ser(writer);

    ser.Serialize(obj);
    ser.Flush();
  }

  template <typename ReadBuffer>
  static Variant Deserialize(ReadBuffer& buf) {
    typedef MsgPackReader<ReadBuffer> reader_type;

    typedef Deserializer<ReadBuffer, reader_type> msgpack_deserializer;

    return msgpack_deserializer::Deserialize(buf);
  }
};

//default use msgpack protocol
TB_ARCHIVE_API void SerVariantAsBinary(const Variant& val, MemoryBuffer& buf);
TB_ARCHIVE_API void DeserBinaryAsVariant(MemoryBuffer& data, Variant& val);
TB_ARCHIVE_API void DeserBinaryAsVariant(const char* data, uint32 len, Variant& val);

//use rapidjson implementation, pretty output	
TB_ARCHIVE_API void SerVariantAsJson(const Variant& val, MemoryBuffer& buf);
TB_ARCHIVE_API void DeserJsonAsVariant(MemoryBuffer& data, Variant& val);
TB_ARCHIVE_API void DeserJsonAsVariant(const char* data, uint32 len, Variant& val);

TB_NAMESPACE_END

#endif //TB_ARCHIVE_MARSHAL_HPP__
